⚡ 30 秒速记

  • 合成事件包装原生事件并分发组件回调
  • 多数事件委托到根,特殊事件另有处理
  • 捕获、冒泡与默认行为分别控制
  • 原生对象可经 nativeEvent 获取
  • 门户按组件树传播,版本影响事件池等细节

React 事件是在浏览器事件之上组织组件回调的一层接口。 多数事件由根容器接收,再按组件关系分发捕获与冒泡处理,业务拿到的是包装后的事件对象,需要时还能访问原生事件。阻止传播和阻止默认行为是不同操作,混合原生监听时要看实际注册位置。门户等场景还说明,组件事件传播不完全等同于页面节点的直观嵌套。

版本校准: 本文若分析 ReactDOM.render、旧生命周期或栈调和,应把它视为理解架构演进的历史路径。React 19 已移除 ReactDOM.render,当前客户端入口使用 createRoot;并发渲染也必须区分可中断的渲染阶段与同步提交阶段。迁移前对照 React 19 官方升级指南。

注:本文逻辑提取自 React 16.13.x。随着 React 版本的更迭,事件系统的实现细节难免有调整,但其设计思想总是一脉相承的,你只要把握住核心逻辑即可。

# 回顾原生 DOM 下的事件流

在浏览器中,我们通过事件监听来实现 JS 和 HTML 之间的交互。一个页面往往会被绑定许许多多的事件,而页面接收事件的顺序,就是事件流。

W3C 标准约定了一个事件的传播过程要经过以下 3 个阶段:

  • 事件捕获阶段
  • 目标阶段
  • 事件冒泡阶段

当事件被触发时,首先经历的是一个捕获过程:事件会从最外层的元素开始“穿梭”,逐层“穿梭”到最内层元素,这个过程会持续到事件抵达它目标的元素(也就是真正触发这个事件的元素)为止;此时事件流就切换到了“目标阶段”——事件被目标元素所接收;然后事件会被“回弹”,进入到冒泡阶段——它会沿着来时的路“逆流而上”,一层一层再走回去。

# DOM 事件流下的性能优化思路:事件委托

在原生 DOM 中,事件委托(也叫事件代理)是一种重要的性能优化手段。这里我通过一道面试题,来快速地帮你回忆相关的知识。

请看下面这段代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <ul id="poem">
    <li>床前明月光</li>
    <li>疑是地上霜</li>
    <li>举头望明月</li>
    <li>低头思故乡</li>
    <li>锄禾日当午</li>
    <li>汗滴禾下土</li>
    <li>谁知盘中餐</li>
    <li>粒粒皆辛苦</li>
    <li>背不动了</li>
    <li>我背不动了</li>
  </ul>
</body>
</html>
webapp
公众号
开发者导航
切换夜间模式
点击侧边栏上一篇
点击侧边栏下一篇
折叠侧边栏
收起全部